#pragma once
#include <queue>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModle;

    static int gcap = 10;

    template <class T>
    class BlockQueue
    {
        bool IsEmpty() { return _q.empty(); }
        bool IsFull() { return _q.size() == _cap; }

    public:
        BlockQueue(int cap = gcap) : _cap(gcap), _cwait_num(0), _pwait_num(0)
        {
        }

        void Equeue(T &data)
        {
            _mutex.lock();

            while (IsFull())
            {
                printf("生产者进入等待...\n");
                _pwait_num++;
                _ProducerCond.wait(_mutex);
                _pwait_num--;
                printf("生产者被唤醒...\n");
            }
            _q.push(data);

            if (_cwait_num > 0)
            {
                printf("唤醒消费者\n");
                _ConsumerCond.signal();
            }
            _mutex.unlock();
        }

        void Pop(T &data)
        {
            _mutex.lock();

            while (IsEmpty())
            {
                printf("消费者进入等待...\n");
                _cwait_num++;
                _ConsumerCond.wait(_mutex);
                _cwait_num--;
                printf("消费者被唤醒...\n");
            }
            data = _q.front();
            _q.pop();

            if (_pwait_num > 0)
            {
                
                printf("唤醒生产者...\n");
                _ProducerCond.signal();
            }
            _mutex.unlock();
        }

        ~BlockQueue()
        {
        }

    private:
        std::queue<T> _q;
        int _cap;
        Mutex _mutex;
        Clone _ConsumerCond;
        Clone _ProducerCond;
        int _cwait_num;
        int _pwait_num;
    };
}
